﻿using System;
using System.Diagnostics;
using System.Web;

namespace Wisdom.Core
{
    public abstract class ExtendedHttpApplication : HttpApplication
    {
        private static readonly object syncLock = new object();
        private volatile static IApplication app;

        /// <summary>
        /// Gets the app. 
        /// </summary> 
        /// <value>
        /// The app.
        /// </value>
        public IApplication App
        {
            get
            {
                if (app == null)
                {
                    lock (syncLock)
                    {
                        if (app == null)
                        {
                            app = this.CreateApplication(AppRuntime.Instance);
                            
                            this.RegisterBootstrapperTasks(app.Bootstrapper.BootstrapperTasks);
                            this.RegisterPerRequestTasks(app.Bootstrapper.PerRequestTasks);
                            this.RegisterServices(app.ObjectContainer);
                        }
                    }
                }
                return app;
            }
        }
        /// <summary>
        /// Creates the app. 
        /// </summary> 
        /// <returns/>
        protected abstract IApplication CreateApplication(AppRuntime appRuntime);

        protected virtual void RegisterServices(IServiceRegistrar objectContainer) { }

        protected virtual void RegisterBootstrapperTasks(IBootstrapperTasksRegistry bootstrapperTasks){}

        protected virtual void RegisterPerRequestTasks(IPerRequestTasksRegistry perRequestTasks){}
        
        /// <summary>
        /// Gets the container. 
        /// </summary> 
        /// <value>
        /// The container.
        /// </value>
        public IObjectContainer Container
        {
            get { return this.App.ObjectContainer; }
        }

        /// <summary>
        /// Executes custom initialization code after all event handler modules have been added.
        /// 
        /// </summary>
        public override void Init()
        {
            base.Init();
            this.BeginRequest += this.HandleBeginRequest;
            this.EndRequest += this.HandleEndRequest;
        }

        /// <summary>
        /// Fires when the application starts. 
        /// </summary>
        protected void Application_Start()
        {
            this.App.Start();
            this.OnStart();
        }

        /// <summary>
        /// Fires when the application ends. 
        /// </summary>
        protected void Application_End()
        {
            this.OnEnd();
            this.App.End();
        }

        /// <summary>
        /// Executes when the application starts.
        /// 
        /// </summary>
        protected virtual void OnStart()
        {
        }

        /// <summary>
        /// Called when request starts.
        /// 
        /// </summary>
        protected virtual void OnBeginRequest(HttpContextBase context)
        {
            this.OnPerRequestTasksExecuting();
            bool flag = false;
            var perRquestTasks = this.GetCurrentContainer()
                                     .GetServices<IPerRequestTask>();
                
            foreach (IPerRequestTask perRequestTask in perRquestTasks)
            {
                if (flag)
                {
                    flag = false;
                }
                else
                {
                    TaskContinuation taskContinuation = perRequestTask.Execute();
                    if (taskContinuation != TaskContinuation.Break)
                        flag = taskContinuation == TaskContinuation.Skip;
                    else
                        break;
                }
            }
            this.OnPerRequestTasksExecuted();
        }

        /// <summary>
        /// Executes before the registered <see>
        ///                                    <cref>T:IPerRequestTask</cref>
        ///                                </see>
        ///     executes.
        /// 
        /// </summary>
        protected virtual void OnPerRequestTasksExecuting()
        {
        }

        /// <summary>
        /// Executes after the registered <see>
        ///                                   <cref>T:IPerRequestTask</cref>
        ///                               </see>
        ///     executes.
        /// 
        /// </summary>
        protected virtual void OnPerRequestTasksExecuted()
        {
        }

        /// <summary>
        /// Executes when the request ends.
        /// 
        /// </summary>
        protected virtual void OnEndRequest(HttpContextBase context)
        {
            this.OnPerRequestTasksDisposing();
            this.GetCurrentContainer()
                .GetServices<IPerRequestTask>()
                .Each(task => task.Dispose());
            this.OnPerRequestTasksDisposed();
        }

        /// <summary>
        /// Executes before the registered <see>
        ///                                    <cref>T:IPerRequestTask</cref>
        ///                                </see>
        ///     disposes.
        /// 
        /// </summary>
        protected virtual void OnPerRequestTasksDisposing()
        {
        }

        /// <summary>
        /// Executes after the registered <see>
        ///                                   <cref>T:IPerRequestTask</cref>
        ///                               </see>
        ///     disposes.
        /// 
        /// </summary>
        protected virtual void OnPerRequestTasksDisposed()
        {
        }

        /// <summary>
        /// Executes when the application ends.
        /// 
        /// </summary>
        protected virtual void OnEnd()
        {
        }

        /// <summary>
        /// Gets the current adapter. 
        /// </summary> 
        /// <returns/>
        protected virtual IObjectContainer GetCurrentContainer()
        {
            return this.Container;
        }

        private void HandleBeginRequest(object sender, EventArgs e)
        {
            this.OnBeginRequest(new HttpContextWrapper(this.Context));
        }

        private void HandleEndRequest(object sender, EventArgs e)
        {
            this.OnEndRequest(new HttpContextWrapper(this.Context));
        }
    }
}